package plp.prolog.declaration;

import java.util.ArrayList;

import plp.prolog.memory.AmbienteExecucaoProlog;

public class Fato implements Relacao, Expressao{
	private Predicado predicado;
	private ArrayList<Termo> args;

	public Fato(Predicado predicado, ArrayList<Termo> args) {
		this.predicado = predicado;
		this.args = args;
	}

	@Override
	public boolean unificar(AmbienteExecucaoProlog ambienteExecucao,
			Relacao relacao) {
		
		return ambienteExecucao.resolverUnificacoes(this, relacao);
		
	}
	
	@Override
	public boolean avaliar(AmbienteExecucaoProlog ambienteExecucao, Relacao relacao) {

		if (relacao == null) return false;
		
		if(relacao instanceof Fato){
			Fato fatoCombinado = (Fato) relacao;
		
			if (this.predicado.getPred().compareTo(fatoCombinado.getPredicado().getPred()) == 0 &&
					this.args.size() == fatoCombinado.args.size()) {
		
				return ambienteExecucao.resolverUnificacoes(this, relacao);
			}else{
				return false;
			}
		
		}else if (relacao instanceof Regra){
			Regra regraCombinado = (Regra) relacao;
			
			if(regraCombinado.getFato().avaliar(ambienteExecucao, this)){
				ambienteExecucao.incrementa();
				boolean retorno = regraCombinado.getExpressao().avaliar(ambienteExecucao, relacao);
				if(retorno){
					ambienteExecucao.printUnificacoes();
				}
				ambienteExecucao.restaura();
				return retorno;
			}
		}
		
		return true;

	}
	
	@Override
	public Termo getTermo(int index){
		return args.get(index);
	}

	@Override
	public String toString() {
		return "Fato [predicado=" + predicado.getPred() + ", args=" + args + "]";
	}

	public Predicado getPredicado() {
		return predicado;
	}

	public ArrayList<Termo> getArgs() {
		return args;
	}

	@Override
	public Fato getFatoASerCombinado() {
		return this;
	}

}
